package br.senai.sc.web.amostras.beans;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.faces.bean.ViewScoped;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.inject.Inject;
import javax.inject.Named;

import org.apache.commons.lang3.StringUtils;
import org.jboss.seam.international.status.Messages;
import org.jboss.seam.international.status.builder.BundleKey;
import org.primefaces.model.chart.CartesianChartModel;
import org.primefaces.model.chart.ChartModel;
import org.primefaces.model.chart.ChartSeries;

import br.senai.sc.controller.Parametro;
import br.senai.sc.controller.Qualidade;
import br.senai.sc.controller.business.CondicaoClimaticaBusiness;
import br.senai.sc.controller.business.PontoColetaBusiness;
import br.senai.sc.controller.crud.AmostraCRUD;
import br.senai.sc.controller.crud.BaciaHidrograficaCRUD;
import br.senai.sc.controller.crud.CidadeCRUD;
import br.senai.sc.controller.crud.CondicaoClimaticaCRUD;
import br.senai.sc.controller.crud.PontoColetaCRUD;
import br.senai.sc.controller.exception.BusinessException;
import br.senai.sc.model.Amostra;
import br.senai.sc.model.BaciaHidrografica;
import br.senai.sc.model.Cidade;
import br.senai.sc.model.CondicaoClimatica;
import br.senai.sc.model.PontoColeta;
import br.senai.sc.util.SystemConstants;

/**
 * Classe responsável pelas ações das páginas relacionadas ao cadastro de
 * amostras.
 * 
 * @author Fernando Marquardt &lt;fernando.marquardt@sc.senai.br&gt;
 * @since 02/02/2012
 * @version $Id: AmostrasBean.java 28 2012-03-07 20:48:20Z fernando.marquardt $
 */
@Named
@ViewScoped
public class AmostrasBean implements Serializable {

	private static final long serialVersionUID = 1L;

	@Inject
	private AmostraCRUD amostraCRUD;

	@Inject
	private BaciaHidrograficaCRUD baciaHidrograficaCRUD;

	@Inject
	private CondicaoClimaticaCRUD condicoesClimaticasCRUD;

	@Inject
	private PontoColetaCRUD pontoColetaCRUD;

	@Inject
	private PontoColetaBusiness pontoColetaBusiness;

	@Inject
	private CondicaoClimaticaBusiness condicaoClimaticaBusiness;

	@Inject
	private CidadeCRUD cidadeCRUD;

	@Inject
	private Messages messages;

	/**
	 * Amostra em edição.
	 */
	private Amostra amostra;

	/**
	 * Lista de amostras cadastradas.
	 */
	private DataModel<Amostra> amostras;

	/**
	 * Bacia hidrográfica selecionada na tela de cadastro.
	 */
	private BaciaHidrografica baciaHidrografica;

	/**
	 * Cidade selecionada na tela de cadastro.
	 */
	private Cidade cidade;

	/**
	 * Inicia o cadastro de uma amostra, com os valores inicias do formulário.
	 */
	public void cadastrarAmostra() {
		amostra = new Amostra();
		amostra.setData(new Date());
		baciaHidrografica = null;
		cidade = null;
	}

	/**
	 * Carrega uma amostra para edição e calcula os valores dos parâmetros.
	 */
	public void carregarAmostra() {
		amostra = amostras.getRowData();

		PontoColeta pontoColeta = amostra.getPontoColeta();
		baciaHidrografica = pontoColeta.getCorpoHidrico()
				.getBaciaHidrografica();
		cidade = pontoColeta.getCidade();
	}

	/**
	 * Persiste os dados de uma amaostra no banco e recalcula os parâmetros
	 * apresentados no gráfico.
	 */
	public void salvarAmostra() {
		try {
			amostra = amostraCRUD.salvar(amostra);

			amostras = null;
			messages.info(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"amostras.cadastrar.sucesso"));
		} catch (BusinessException e) {
		}

	}

	/**
	 * Remove uma amostra do banco.
	 */
	public void removerAmostra() {
		try {
			amostraCRUD.remover(amostra);
		} catch (BusinessException e) {
		}
	}

	/**
	 * Reseta o campo de cidade ao mudar a bacia hidrográfica selecionada.
	 */
	public void mudarBaciaHidrografica() {
		cidade = null;
		mudarCidade();
	}

	/**
	 * Reseta o ponto de coleta ao mudar a cidade selecionada.
	 */
	public void mudarCidade() {
		amostra.setPontoColeta(null);
	}

	/**
	 * Utilizado para apresentar o formulário de cadastro ou mostrar mensagem de
	 * que precisa ter {@link PontoColeta} cadastrado.
	 * 
	 * @see PontoColetaBusiness#existePontoColetaCadastrado()
	 * 
	 * @return
	 */
	public boolean existePontoColetaCadastrado() {
		return pontoColetaBusiness.existePontoColetaCadastrado();
	}

	/**
	 * Utilizado para apresentar o formulário de cadastro ou mostrar mensagem de
	 * que precisa ter {@link CondicaoClimatica} cadastrada.
	 * 
	 * @see CondicaoClimaticaBusiness#existeCondicaoClimaticaCadastrada()
	 * 
	 * @return
	 */
	public boolean existeCondicaoClimaticaCadastrada() {
		return condicaoClimaticaBusiness.existeCondicaoClimaticaCadastrada();
	}

	/**
	 * @return Retorna a lista de amostras cadastradas em forma de
	 *         {@link DataModel}
	 */
	public DataModel<Amostra> getAmostras() {
		if (amostras == null) {
			amostras = new ListDataModel<Amostra>(amostraCRUD.findAmostras());
		}

		return amostras;
	}

	/**
	 * @return Retorna o {@link ChartModel} para montar o gráfico de notas dos
	 *         parâmetros.
	 */
	public ChartModel getGraficoNotasModel() {
		CartesianChartModel model = new CartesianChartModel();

		try {
			for (Parametro parametro : amostra.getParametros()) {
				ChartSeries series = new ChartSeries(parametro.getDescricao()
						.getValor());
				series.set("Nota", parametro.getIqa());
				model.addSeries(series);
			}
		} catch (BusinessException e) {
			// TODO: tratar exceções dos cálculos de IQA
		}

		return model;
	}

	/**
	 * @return Retorna a string com as cores das colunas do gráfico de notas dos
	 *         parâmetros.
	 */
	public String getCoresGraficoNotas() {

		try {
			Parametro parametros[] = amostra.getParametros();

			String[] cores = new String[parametros.length];

			for (int i = 0, c = parametros.length; i < c; i++) {
				cores[i] = Qualidade.getQualidade(parametros[i].getIqa())
						.getCorHexa();
			}

			return StringUtils.join(cores, ",");
		} catch (BusinessException e) {
			// TODO: tratar exceções dos cálculos de IQA
		}

		return null;
	}

	/**
	 * @return Retorna o {@link ChartModel} do gráfico de IQA da amostra.
	 */
	public ChartModel getGraficoIQAModel() {
		CartesianChartModel model = new CartesianChartModel();

		ChartSeries series = new ChartSeries("IQA");
		series.set("Nota", amostra.getIQA());
		model.addSeries(series);

		return model;
	}

	/**
	 * @return Retorna string com a cor da coluna de IQA da amostra.
	 */
	public String getCoresGraficoIQA() {
		return amostra.getQualidade().getCorHexa();
	}

	/**
	 * @return Retorna as bacias hidrográficas apresentadas no formulário de
	 *         cadastro de amostra.
	 */
	public List<BaciaHidrografica> getBaciasHidrograficas() {
		return baciaHidrograficaCRUD.findBaciasHidrograficas();
	}

	/**
	 * @return Retorna as cidadaes apresentadas no formulário de cadastro de
	 *         amostra.
	 */
	public List<Cidade> getCidades() {
		try {
			return cidadeCRUD.findCidades(baciaHidrografica);
		} catch (BusinessException e) {
			messages.info(new BundleKey(
					SystemConstants.PATH_TO_APPLICATION_MESSAGES,
					"bacias.inexistente"));
		}

		return new ArrayList<Cidade>();
	}

	/**
	 * @return Retorna os pontos de coleta apresentados no formulário de
	 *         cadastro de amostra.
	 */
	public List<PontoColeta> getPontosColeta() {
		try {
			return pontoColetaCRUD.findPontosColeta(cidade);
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * @return Retorna as condições climáticas apresentadas no formulário de
	 *         cadastro de amostra.
	 */
	public List<CondicaoClimatica> getCondicoesClimaticas() {
		return condicoesClimaticasCRUD.findCondicoesClimaticas();
	}

	public Date getDataAtual() {
		return new Date();
	}

	public Amostra getAmostra() {
		return amostra;
	}

	public BaciaHidrografica getBaciaHidrografica() {
		return baciaHidrografica;
	}

	public void setBaciaHidrografica(BaciaHidrografica baciaHidrografica) {
		this.baciaHidrografica = baciaHidrografica;
	}

	public Cidade getCidade() {
		return cidade;
	}

	public void setCidade(Cidade cidade) {
		this.cidade = cidade;
	}
}